package org.jadapter.tests;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeSet;

import org.jadapter.Adapter;
import org.jadapter.JAdapter;
import org.jadapter.registry.AdapterRegistry;
import org.jadapter.registry.TransitiveAdapterRegistry;
import org.jadapter.tests.examples.CommaSeparated;
import org.jadapter.tests.examples.SetterAdapter;
import org.jadapter.tests.examples.ConstructorAdapter;
import org.jadapter.tests.examples.SortedMapList;
import org.jadapter.tests.examples.simple.adapters.IA2IB;
import org.jadapter.tests.examples.simple.adapters.IB2IC;
import org.jadapter.tests.examples.simple.api.IA;
import org.jadapter.tests.examples.simple.api.IB;
import org.jadapter.tests.examples.simple.api.IC;
import org.jadapter.tests.examples.simple.impl.A;

import junit.framework.TestCase;

@SuppressWarnings("unchecked")
public class TestAdapterRegistry extends TestCase {

    List list;
    Map<String, String> map;

    
    public void setUp() {
        list = Arrays.asList("foo", "bar");
        
        map = new HashMap<String,String>();
        map.put("Foo", "foo");
        map.put("Bar", "bar");  
    }
    
    public void testShouldFindAdapterAndAdaptObject() {
        AdapterRegistry registry = new TransitiveAdapterRegistry();

        registry.register(IA2IB.class, IB.class, IA.class);
        IB b = registry.transform(new A(), IB.class);
        assertNotNull("A -> B", b);
        
        registry.register(IB2IC.class, IC.class, IB.class);
        IC c = registry.transform(b, IC.class);
        assertNotNull("B -> C", c);
        
    }
    
    public void testShouldAdaptImplementations() {        
        Adapter adapter = new JAdapter(SetterAdapter.class)
            .from(List.class).to(CommaSeparated.class);
        
        AdapterRegistry registry = new TransitiveAdapterRegistry();     
        
        registry.register(adapter);
        CommaSeparated cs = registry.transform(list, CommaSeparated.class);
        assertNotNull(cs);                
    }
    
    
    public void testShouldRegisterAndAdaptAdapterFactories() {
        AdapterRegistry registry = new TransitiveAdapterRegistry();

        
        registry.register(new SortedMapList());
        SortedMap map = registry.transform(list, SortedMap.class);
        
        assertTrue(map.containsKey(1));
        assertTrue(map.containsValue("foo"));
        
    }

    
    public void testShouldAdaptToSuperInterfaces() {
        AdapterRegistry registry = new TransitiveAdapterRegistry();        
        registry.register(new SortedMapList());
        Map map = registry.transform(list, Map.class);
        // Map is a super interface of SortedMap, 
        // the registry should find that for us
        assertTrue(map.containsKey(1));
        assertTrue(map.containsValue("foo"));        
    }
    
    
    
    @SuppressWarnings("serial")
    public void testImplicitJAdapter() throws Exception {
        AdapterRegistry registry = new TransitiveAdapterRegistry();
        
        registry.register(ConstructorAdapter.class, CommaSeparated.class, Map.class);
        CommaSeparated cs = registry.transform(new HashMap<Object,Object>(), CommaSeparated.class);
        assertNotNull("simple register api fails to ", cs);
        
        Map<String,String> anonMap = new HashMap<String,String>(){{put("anony", "map");}};
        cs = registry.transform(anonMap, CommaSeparated.class);
        assertNotNull("instance with init code fails", cs);
    }
    


    public void testShouldThrowExceptionWhenNotFound() {
             
        Adapter listAdapter = new JAdapter<CommaSeparated,List> (
                SetterAdapter.class,
                CommaSeparated.class,
                List.class);
        
        Adapter mapAdapter = new JAdapter(ConstructorAdapter.class)
            .from(Map.class).to(CommaSeparated.class);
        
        AdapterRegistry registry = new TransitiveAdapterRegistry();
        registry.register(listAdapter);
        registry.register(mapAdapter);
        
        try {
            registry.transform(new HashMap<Object,Object>(), List.class);
            fail("no adapters for HashMap->List");
        } catch (RuntimeException e) {
            // expected
        }
        
        
        try {
            registry.transform(new TreeSet<String>(), CommaSeparated.class);
            fail("no adapters for TreeSet->CommaSeparated");
        } catch (RuntimeException e) {
            // expected
        }
    }
    
}
